<template>
  <div>
    <div class="flex flex-wrap">
      <div v-for="(item, index) in urlList" :key="index">
        <div
          class="relative flex items-center"
          @mouseenter="selectIndex = index"
          @mouseleave="selectIndex = -1"
        >
          <audio controls style="width: 260px; height: 40px">
            <source :src="item" type="audio/ogg" />
          </audio>
          <!-- 删除按钮 -->
          <div v-if="!disabled" class="ml-1" @click="onRemove(item, index)">
            <Icon color="red" icon="material-symbols:delete-outline" />
          </div>
        </div>
      </div>
      <div v-if="urlList.length == 0 && disabled" class="text-[#999]">--</div>
      <div v-if="urlList.length < limit && !disabled">
        <ElUpload
          :headers="headers"
          :action="api"
          :accept="accept"
          :show-file-list="false"
          :on-error="onError"
          :on-success="onSuccess"
          :on-progress="onProgress"
          :on-change="onChange"
          :on-exceed="onExceed"
          :before-upload="beforeUpload"
          :data="paramsComp"
          :multiple="multiple"
          :limit="limit - urlList.length"
        >
          <div>
            <slot name="uploadBtn">
              <div
                class="flex flex-col items-center justify-center bg-[#fff] border"
                :class="divClass"
              >
                <Icon class="text-[a9aeb6]" icon="fluent:add-16-filled" />
              </div>
            </slot>
          </div>
        </ElUpload>
      </div>
    </div>

    <ElImageViewer
      hide-on-click-modal
      v-if="previewVisible && urlList && urlList.length"
      :url-list="urlList"
      :initial-index="previewIndex"
      @close="closePreview"
    ></ElImageViewer>
  </div>
</template>

<script lang="ts" setup>
import { ref, onMounted, watch, type PropType, computed } from 'vue'

import type {
  UploadFile,
  UploadFiles,
  UploadProgressEvent,
  UploadUserFile,
  UploadRawFile,
} from 'element-plus'

import { ElMessage, useFormItem, ElImageViewer, ElUpload } from 'element-plus'
import { cloneDeep, isArray, isObject, isUndefined } from 'lodash-es'
import { propTypes } from '@/types/propTypes'
import { Icon } from '@iconify/vue'
import { objKeyAes } from '@/utils/gloab'

const { formItem } = useFormItem()
const props = defineProps({
  modelValue: {
    type: [String, Array] as PropType<string | string[] | ModelValueObj[]>,
  },
  // modelValue 类型
  modelType: propTypes.oneOf(['string', 'stringArray', 'ObjArray']).def('string'),
  // 请求接口
  api: {
    type: String,
    default: '/admin-api/common/upload',
  },
  // 是否支持多选
  multiple: {
    type: Boolean,
    default: false,
  },
  // 支持上传的类型
  accept: {
    type: String,
    default: 'audio/x-m4a,audio/mpeg,video/mp4,wav',
  },
  // 文件上传个数限制
  limit: {
    type: Number,
    default: 1,
  },
  // 是否禁用
  disabled: {
    type: Boolean,
    default: false,
  },
  //图片样式
  divClass: {
    type: String,
    default: 'w-[60px] h-[60px] rounded-[6px] mr-[10px]',
  },
  // 上传前函数
  beforeUpload: propTypes.func,
  // 上传时附带的额外参数
  params: {
    type: Object,
    default: {},
  },
  // 文件大小限制
  maxSize: propTypes.number,
  /**是否对参数排序加密 */
  isKeyAes: {
    type: Boolean,
    default: true,
  },
  /**请求头信息 */
  headers: {
    type: Object,
    default: {},
  },
})

// 文件列表
const urlList = ref<string[]>([])

// 预览下标
const previewIndex = ref<number>(0)
// 控制预览组件
const previewVisible = ref<boolean>(false)
let selectIndex = ref<number>(-1)
interface ModelValueObj {
  fileName?: string
  filePath?: string
}
type ModelType = string | string[] | ModelValueObj[]

const emits = defineEmits([
  'update:model-value',
  'on-preview',
  'on-remove',
  'on-success',
  'on-error',
  'on-progress',
  'on-change',
  'on-exceed',
  'before-upload',
  'before-remove',
])

watch(
  () => props.modelValue,
  (val) => {
    if (val) {
      if (isArray(val)) {
        if (isObject(val)) {
          urlList.value = val.map((url: ModelValueObj) => url.filePath) as string[]
        } else {
          urlList.value = (val as string[]).map((url: string) => url)
        }
      } else {
        urlList.value = val ? [val] : []
      }
    }
  },
  {
    deep: true,
    immediate: true,
  },
)
const paramsComp = computed(() => {
  let data = props.isKeyAes ? objKeyAes(props.params) : props.params
  return data
})
function formatToken(token: null | string) {
  return token ? `Bearer~~${token}` : null
}
// 预览
const onPreview = (index: number) => {
  selectIndex.value = -1
  previewVisible.value = true
  previewIndex.value = index
}

// 上传失败
const onError = () => {
  ElMessage.warning({ message: '上传失败' })
}

// 上传成功
const onSuccess = (response: any, file: any, fileList: any) => {
  console.log('上传成功', response, fileList)
  if (response.code == 422) {
    return ElMessage.warning({ message: response.data })
  }

  let dataOne: ModelType = ''
  if (props.modelType == 'string') {
    dataOne = response.data.filePath
  } else if (props.modelType == 'stringArray') {
    let fileListd = isArray(props.modelValue) ? cloneDeep(props.modelValue) : []
    dataOne = [...fileListd, response.data.filePath] as string[]
  } else {
    let fileListd = isArray(props.modelValue) ? cloneDeep(props.modelValue) : []
    dataOne = [...fileListd, response.data] as ModelValueObj[]
  }
  emits('update:model-value', dataOne)
  emits('on-success', response.data)
  formItem?.validate?.('change')
}
// 当超出限制时，执行的钩子函数
function onExceed(files: File[], uploadFiles: UploadUserFile[]) {
  // console.log('files', files, uploadFiles);
  ElMessage({
    message: '选择文件数超出最大上传数' + (props.limit - urlList.value.length),
    type: 'warning',
  })
}

// 移除文件
const onRemove = (item: string, index: number) => {
  selectIndex.value = -1
  if (props.limit == 1) {
    urlList.value = []
    emits('update:model-value', '')
    emits('on-remove', '')
    formItem?.validate?.('change')
  } else {
    let fileListd = isArray(props.modelValue) ? cloneDeep(props.modelValue) : []
    fileListd.splice(index, 1)
    emits('update:model-value', fileListd)
    emits('on-remove', fileListd)
    formItem?.validate?.('change')
  }
}

const onProgress = (evt: UploadProgressEvent, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
  console.log('文件上传时的钩子')

  emits('on-progress', evt, uploadFile, uploadFiles)
}

const onChange = (uploadFile: UploadFile, uploadFiles: UploadFiles) => {
  emits('on-change', uploadFile, uploadFiles)
}

const beforeUpload = (rawFile: UploadRawFile) => {
  const { maxSize, accept } = props
  // emits('before-upload', rawFile);

  // 文件后缀名截取
  const suffix = rawFile.name.substring(rawFile.name.lastIndexOf('.') + 1)
  console.log('error', suffix, accept)

  if (!isUndefined(accept) && accept!.indexOf(suffix) == -1) {
    ElMessage({
      message: `请上传${accept}格式文件`,
      type: 'warning',
    })
    return false
  }

  if (!isUndefined(maxSize) && rawFile.size / 1024 / 1024 > maxSize) {
    ElMessage({
      message: `上传文件大小不能超过 ${maxSize} MB!`,
      type: 'warning',
    })
    return false
  }

  // 扩展 beforeUpload 验证
  if (typeof props.beforeUpload === 'function') {
    return props.beforeUpload(rawFile)
  }

  return true
}

// 关闭遮罩
const closePreview = () => {
  previewVisible.value = false
}
</script>

<style lang="scss" scoped></style>
